﻿using System;
using System.ComponentModel;
using RoMFramework.RomAPI.Offsets;

namespace RoMFramework.RomAPI.Objects
{
    public class RomPlayer : RomUnit
    {
        public PointerManager m_Pointers;
        public uint SwimAddress;

        /// <summary>
        /// Constructor - passing client reference to parent (A <see cref="RomUnit"/>)
        /// </summary>
        /// <param name="client">Client the object is being created for</param>
        /// <param name="basePointer">Base pointer of this object</param>
        /// <param name="pointerManager">Pointer manager of the client object</param>
        public RomPlayer(RomClient client, uint basePointer, PointerManager pointerManager) : base(client, basePointer)
        {
            m_Pointers = pointerManager;
        }

        /// <summary>
        /// Finds the SwimAddress Flag
        /// </summary>
        private void GetSwimPointer()
        {
            try
            {
                SwimAddress = GetPointerAddress(BaseAddress + (uint)RomPlayerOffset.SWIMHACK1);
                SwimAddress += (uint)RomPlayerOffset.SWIMHACK2;
            }
            catch (Exception ex)
            {
                
                RoMFramework.Console.Instance.AddLine(ex.Message);
            }
        }

        [Category("Player Stats"), DescriptionAttribute("The Player Climb Angle")]
        public float ClimbAngle
        {
            get
            {
                return GetExternalField<float>(m_Pointers.PointerToUint("CharacterClimbAngle"));
            }

            set
            {
                SetProtectedField<float>(m_Pointers.PointerToUint("CharacterClimbAngle"), value);
            }
        }

        [Category("Player Stats"), DescriptionAttribute("Whether the player is swimming")]
        public uint SwimFlag
        {
            get
            {
                GetSwimPointer();
                return GetExternalField<uint>(SwimAddress);
            }

            set
            {
                GetSwimPointer();
                if (SwimAddress == 0) return;
                SetProtectedField<uint>(SwimAddress, value);
            }
        }

        /// <summary>
        /// Writes the specified movement flags to the player
        /// Because we like dicks it is possible to specify multiple movement commands by using the | operator
        /// e.g. RomUnitMovement.Forward | RomUnitMovement.Strafe_Left.
        /// However, you are not able to do RomUnitMovement.Forward | RomUnitMovement.Backward. Fag.
        /// </summary>
        /// <param name="movement">The movement flag to write</param>
        /// <param name="Overwrite">Whether or not to overwrite the current movement flag</param>
        public void Move(RomUnitMovement movement, bool Overwrite = true)
        {
            try
            {
                byte original = GetExternalField<Byte>((Client.m_BasePlayerAddress + (uint) RomPlayerOffset.MOVEMENT));
                if (Overwrite)
                {
                    original = 0x00;
                }
                original |= (byte) movement;
                SetExternalField<UInt32>(Client.m_BasePlayerAddress + (uint)RomPlayerOffset.MOVEMENT, original);
                //SetField<UInt32>((uint)RomPlayerOffset.MOVEMENT, (UInt32)movement);
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.Message);
            }
        }
    }
}
